////////////////////////////////////////////////////////////////////////////////
// This file is part of the Mist compiler.                                    //
//                                                                            //
// Copyright (C) 2009 The Mist project                                        //
//                                                                            //
// For a list of contributors, see the COMMITTERS file.                       //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// in the COPYING file. If not, see <http://www.gnu.org/licenses/>.           //
////////////////////////////////////////////////////////////////////////////////

///
/// \file
/// Contains the implementation of the operator class methods.
///

#include "operator.hpp"

////////////////////////////////////////////////////////////////////////////////
// Includes                                                                   //
////////////////////////////////////////////////////////////////////////////////

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

#include <boost/tokenizer.hpp>
using boost::char_separator;
using boost::tokenizer;

#include <cctype>

#include "common/assert.hpp"
#include "common/string.hpp"
#include "common/vector.hpp"
#include "parse.hpp"

////////////////////////////////////////////////////////////////////////////////
// Function Implementations                                                   //
////////////////////////////////////////////////////////////////////////////////

bool Operator::binds_tighter_than(sptr<Operator> other) const {
	return precedence() > other->precedence();
}

////////////////////////////////////////////////////////////////////////////////

SingleOperator::SingleOperator(const string& f) {
	_info = parseOperator(f);
	
	_operandCount = 0;
	foreach (string s, _info)
		_operandCount += s.empty();
	
	_precedence = 0;
	
	#define OPERATOR(str, fname, assoc, spaces) \
		if (_info == parseOperator(str)) {      \
			_functionName = fname;              \
			_associativity = assoc;             \
			_spaces = spaces;                   \
			return;                             \
		}
	
	#define ______________________________________________________________________ _precedence--;
	
	// Here follows the table of Mist operators, sorted by descending precedence
	// and grouped by precedence using the local horizontal rule macro. The
	// operator description includes its notation (with operand locations), its
	// associativity and the prefered number of spaces between operands and
	// operator.
	//
	______________________________________________________________________
	
	OPERATOR( "1 ( 2 )", "call"       , NON_ASSOCIATIVE, 0 )
	OPERATOR( "1 [ 2 ]", "subscript"  , NON_ASSOCIATIVE, 0 )
	______________________________________________________________________
	
	OPERATOR( "  ! 1", "not"       , NON_ASSOCIATIVE, 0 )
	OPERATOR( "  # 1", "count"     , NON_ASSOCIATIVE, 0 )
	OPERATOR( "  - 1", "negative"  , NON_ASSOCIATIVE, 0 )
	OPERATOR( "  + 1", "positive"  , NON_ASSOCIATIVE, 0 )
	OPERATOR( "new 1", "new_value" , NON_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1  *  2", "multiply", LEFT_ASSOCIATIVE, 1 )
	OPERATOR( "1  /  2", "divide"  , LEFT_ASSOCIATIVE, 1 )
	OPERATOR( "1 mod 2", "modulo"  , LEFT_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 + 2", "add"     , LEFT_ASSOCIATIVE, 1 )
	OPERATOR( "1 - 2", "subtract", LEFT_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 .. 2", "interval", LEFT_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 =   2", "equal"        , CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 <   2", "smaller"      , CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 >   2", "greater"      , CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 <=  2", "smaller_equal", CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 >=  2", "greater_equal", CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 <>  2", "inequal"      , CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 <>= 2", "comparable"   , CHAIN_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 and 2", "conjunct", LEFT_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 or 2", "disjunct", LEFT_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1  ==> 2", "implies"      , CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 <==  2", "implied"      , CHAIN_ASSOCIATIVE, 1 )
	OPERATOR( "1 <==> 2", "logical_equal", CHAIN_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "if ( 1 ) then 2 else 3", "ternary", NON_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 <- 2", "assign", RIGHT_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	OPERATOR( "1 <-> 2", "swap", NON_ASSOCIATIVE, 1 )
	______________________________________________________________________
	
	assert(false);
	
	#undef ______________________________________________________________________
	#undef OPERATOR
}

vector<string> SingleOperator::parseOperator(const string& f) {
	vector<string> result;
	char_separator<char> sep(" \t\n");
	tokenizer<char_separator<char> > tokens(f, sep);
	foreach (string token, tokens) {
		if (isdigit(token[0]))
			result.push_back("");
		else
			result.push_back(token);
	}
	return result;
}

bool SingleOperator::operator==(const Operator& other) const {
	if (typeid(other) != typeid(SingleOperator))
		return false;
	
	return _info == dynamic_cast<const SingleOperator&>(other)._info;
}

string SingleOperator::function_name() const {
	return _functionName;
}

Associativity SingleOperator::associativity() const {
	return _associativity;
}

ushort SingleOperator::operand_count() const {
	return _operandCount;
}

ushort SingleOperator::spaces() const {
	return _spaces;
}

vector<string> SingleOperator::echo() const {
	return _info;
}

string SingleOperator::get_format() const {
	string result;
	
	uint index = 0;
	for (uint i = 0; i < _info.size(); ++i) {
		if (_info[i].empty())
			result += "%" + to_string(++index) + "%";
		else
			result += _info[i];
		
		if (i < _info.size() - 1)
			result += string(spaces(), ' ');
	}
	
	return result;
}

ushort SingleOperator::precedence() const {
	return _precedence;
}

////////////////////////////////////////////////////////////////////////////////

CompositeOperator::CompositeOperator(sptr<SingleOperator> op) {
	add(op);
}

void CompositeOperator::add(sptr<SingleOperator> op) {
	assert(_operators.empty() || operand_count() == 1);
	_operators.push_back(op);
}

vector<wptr<SingleOperator> > CompositeOperator::operators() const {
	return weak_vector(_operators);
}

bool CompositeOperator::operator==(const Operator& other) const {
	if (typeid(other) != typeid(CompositeOperator))
		return false;
	
	const CompositeOperator& o = dynamic_cast<const CompositeOperator&>(other);
	
	if (_operators.size() != o._operators.size())
		return false;
	
	for (uint i = 0; i < _operators.size(); ++i)
		if (*_operators[i] != *o._operators[i])
			return false;
	
	return true;
}

Associativity CompositeOperator::associativity() const {
	return _operators.back()->associativity();
}

ushort CompositeOperator::operand_count() const {
	return _operators.back()->operand_count();
}

ushort CompositeOperator::spaces() const {
	return _operators.back()->spaces();
}

vector<string> CompositeOperator::echo() const {
	string f = "%1%";
	
	for (uint i = 0; i < _operators.size() - 1; ++i)
		f = (format(f) % _operators[i]->get_format()).str();
	
	vector<string> result = _operators.back()->echo();
	
	for (uint i = 0; i < result.size(); ++i)
		if (!result[i].empty())
			result[i] = (format(f) % result[i]).str();
	
	return result;
}

string CompositeOperator::get_format() const {
	string result;
	
	vector<string> info = echo();
	
	uint index = 1;
	for (uint i = 0; i < info.size(); ++i) {
		if (info[i].empty())
			result += "%" + to_string(index++) + "%";
		else
			result += info[i];
		
		if (i < info.size() - 1)
			result += string(spaces(), ' ');
	}
	
	return result;
}

ushort CompositeOperator::precedence() const {
	return _operators.back()->precedence();
}
